{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "52c71835",
   "metadata": {},
   "source": [
    "# Python 赋值机制"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46976dca",
   "metadata": {},
   "source": [
    "先看一个例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "346511af",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = [1, 2, 3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "85fc695d",
   "metadata": {},
   "outputs": [],
   "source": [
    "y = x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a69e1ff1",
   "metadata": {},
   "outputs": [],
   "source": [
    "x[1] = 100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "fee1b002",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 100, 3]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f0ea29b",
   "metadata": {},
   "source": [
    "改变变量x的值，变量y的值也随着改变，这与Python内部的赋值机制有关。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b8bc878",
   "metadata": {},
   "source": [
    "## 简单类型的赋值机制\n",
    "\n",
    "先来看这一段代码在Python中的执行过程。\n",
    "```\n",
    "x = 500\n",
    "y = x\n",
    "y = 'foo'\n",
    "```\n",
    "\n",
    "- 第一句`x = 500`\n",
    "\n",
    "Python分配了一个 PyInt 大小的内存 pos1 用来储存对象 500 ，然后，Python在命名空间中让变量 x 指向了这一块内存，注意，整数是不可变类型，所以这块内存的内容是不可变的。\n",
    "\n",
    "内存 |\t命名空间 \n",
    "-- | --\n",
    "pos1 : PyInt(500) (不可变) |\tx : pos1\n",
    "\n",
    "- 第二句`y = x`\n",
    "Python并没有使用新的内存来储存变量 y 的值，而是在命名空间中，让变量 y 与变量 x 指向了同一块内存空间。\n",
    "\n",
    "内存|\t命名空间\n",
    "-- | --\n",
    "pos1 : PyInt(500) (不可变)|\tx : pos1\n",
    "|y : pos1\n",
    "\n",
    "- 第三句`y = 'foo'`\n",
    "\n",
    "Python此时分配一个 PyStr 大小的内存 pos2 来储存对象 foo ，然后改变变量 y 所指的对象。\n",
    "\n",
    "内存\t|命名空间\n",
    "-- | --\n",
    "pos1 : PyInt(500) (不可变)|x : pos1\n",
    "pos2 : PyStr('foo') (不可变)\t|y : pos2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8731904",
   "metadata": {},
   "source": [
    "## 逻辑验证\n",
    "\n",
    "对这一过程进行验证，可以使用 `id()` 函数，该函数返回某个变量在内存中的地址，内存地址一样的变量通常是同一个变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c9f1ac39",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 500"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "bac43d44",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558905936"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "72a5cc15",
   "metadata": {},
   "outputs": [],
   "source": [
    "y = x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "cc43d831",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558905936"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "565eff0c",
   "metadata": {},
   "source": [
    "内存地址一样，说明x和y是同一个对象。也可以用关键字`is`判断："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "46d68283",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x is y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e27f6858",
   "metadata": {},
   "outputs": [],
   "source": [
    "y = 'foo'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "38ad39af",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4533836208"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1e2df43",
   "metadata": {},
   "source": [
    "y的内存变化了，但是x的内存没有变化："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "1ed9a967",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558905936"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec3f099e",
   "metadata": {},
   "source": [
    "Python会为每个出现的对象进行赋值，哪怕它们的值是一样的，例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "4d663896",
   "metadata": {},
   "outputs": [],
   "source": [
    "z = 500"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "e0ffa88f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558906096"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(z)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "64272d51",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z is x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e53a29a",
   "metadata": {},
   "source": [
    "不过，为了提高内存利用效率，对于一些简单的对象，如一些数值较小的int对象，Python采用了重用对象内存的办法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "a1f57abe",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "5e547517",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4507801936"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "c35d4ab8",
   "metadata": {},
   "outputs": [],
   "source": [
    "y = 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "38e40f42",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4507801936"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "735af685",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x is y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b883046",
   "metadata": {},
   "source": [
    "## 容器类型的赋值机制\n",
    "\n",
    "看另一段代码：\n",
    "\n",
    "现在来看另一段代码：\n",
    "```\n",
    "x = [500, 501, 502]\n",
    "y = x\n",
    "y[1] = 600\n",
    "y = [700, 800]\n",
    "```\n",
    "\n",
    "- 第一句`x = [500, 501, 502]`\n",
    "\n",
    "Python为3个PyInt分配内存 pos1 ， pos2 ， pos3 （不可变），然后为列表分配一段内存 pos4 ，它包含3个位置，分别指向这3个内存，最后再让变量 x 指向这个列表。\n",
    "\n",
    "内存 |\t命名空间\n",
    "-- |-- \n",
    "pos1 : PyInt(500) (不可变) |x : pos4\n",
    "pos2 : PyInt(501) (不可变)|\n",
    "pos3 : PyInt(502) (不可变)|\n",
    "pos4 : PyList(pos1, pos2, pos3) (可变)\t|\n",
    "\n",
    "- 第二句`y = x`\n",
    "\n",
    "并没有创建新的对象，只需要将 y 指向 pos4 即可。\n",
    "\n",
    "内存\t|命名空间\n",
    "-- |-- \n",
    "pos1 : PyInt(500) (不可变)|x : pos4\n",
    "pos2 : PyInt(501) (不可变)|y : pos4\n",
    "pos3 : PyInt(502) (不可变)|\n",
    "pos4 : PyList(pos1, pos2, pos3) (可变)\t|\n",
    "\n",
    "- 第三句`y[1] = 600`\n",
    "\n",
    "原来 y[1] 这个位置指向的是 pos2 ，由于不能修改 pos2 的值，所以首先为 600 分配新内存 pos5 。\n",
    "\n",
    "再把 y[1] 指向的位置修改为 pos5 。此时，由于 pos2 位置的对象已经没有用了，Python会自动调用垃圾处理机制将它回收。\n",
    "\n",
    "内存\t|命名空间\n",
    "-- |-- \n",
    "pos1 : PyInt(500) (不可变)|x : pos4\n",
    "pos2 : 垃圾回收|\n",
    "pos3 : PyInt(502) (不可变)|\n",
    "pos4 : PyList(pos1, pos5, pos3) (可变)|\n",
    "pos5 : PyInt(600) (不可变)\t|y : pos4\n",
    "\n",
    "\n",
    "- 第四句`y = [700, 800]`\n",
    "\n",
    "首先创建这个列表，然后将变量 y 指向它。\n",
    "\n",
    "内存\t|命名空间\n",
    "-- |-- \n",
    "pos1 : PyInt(500) (不可变)|x : pos4\n",
    "pos3 : PyInt(502) (不可变)|y : pos8\n",
    "pos4 : PyList(pos1, pos5, pos3) (可变)|\n",
    "pos5 : PyInt(600) (不可变)|\n",
    "pos6 : PyInt(700) (不可变)|\n",
    "pos7 : PyInt(800) (不可变)|\n",
    "pos8 : PyList(pos6, pos7) (可变)|\t\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "018bab34",
   "metadata": {},
   "source": [
    "## 逻辑验证"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "361f70e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = [500, 501, 502]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "a5c3953f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558869696"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "c4e60812",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4558906992, 4558906960, 4558906288)"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(x[0]), id(x[1]), id(x[2])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a92e920",
   "metadata": {},
   "source": [
    "赋值，id(y) 与 id(x) 相同："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "397f6daa",
   "metadata": {},
   "outputs": [],
   "source": [
    "y = x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "2973a4a2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558869696"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "9abe33ad",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y is x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d6d1337",
   "metadata": {},
   "source": [
    "修改 y[1] ，id(y) 并不改变。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "09e231bf",
   "metadata": {},
   "outputs": [],
   "source": [
    "y[1] = 600"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "90844322",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558869696"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70234775",
   "metadata": {},
   "source": [
    "id(x[1]) 和 id(y[1]) 的值改变了："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "02f2ea8d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558906608"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(x[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "3eff85a2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558906608"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(y[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cfc48c78",
   "metadata": {},
   "source": [
    "更改 y 的值，id(y) 的值改变："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "0775c2d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "y = [700, 800]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "8ab931db",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558861888"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad9cf44c",
   "metadata": {},
   "source": [
    "id(x) 的值不变："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "5593544b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4558869696"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63686c6e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
